package com.tender.desensitization.factory.instance;

import com.tender.properties.AppConfigProperties;
import com.tender.utils.ApplicationContextUtil;
import com.tender.desensitization.FieldReflectUtils;
import com.tender.desensitization.filter.FieldEncryptionFilter;
import com.tender.desensitization.filter.FieldFilter;
import com.tender.enums.ErrorTypeEnum;
import com.tender.exceptions.CommonException;
import com.tender.utils.AESUtil;
import com.tender.utils.RSAUtil;
import com.tender.utils.SecretContextUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.Base64;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
public class EncryptionUserWrapperProcessFactory extends AbstractUserWrapperProcessFactory {

    public EncryptionUserWrapperProcessFactory(TypeProcessFactoryFacade factoryFacade) {
        super(factoryFacade, new FieldEncryptionFilter());
    }

    @Override
    public Object processType(Object instance) {
        if (null == instance) {
            return null;
        }

        // 处理用户自定义的包装类
        List<Field> allFields = FieldReflectUtils.getAllFields(instance.getClass());

        for (Field field : allFields) {
            field.setAccessible(true);
            TypeProcessFactory processFactory = getFactoryFacade().getProcessFactory(field.getType());
            if (null != processFactory) {
                try {
                    processFactory.processType(field.get(instance));
                } catch (Exception e) {
                    log.error("******************************************");
                    log.error("【获取值，反射异常】field name：{}, 原始对象：{}，具体异常为：", field.getName(), instance, e);
                    log.error("******************************************");
                }
            } else {
                // 基本数据类型 or String.class 类型
                List<FieldFilter> collect = getIncludeTypeFilters().stream().filter(item -> item.isMatch(field)).collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(collect) && String.class == field.getType()) {
                    String originalValue = "";
                    try {
                        originalValue = (String) field.get(instance);
                        String encrypt = encryptFieldValue(originalValue);
                        field.set(instance, encrypt);
                    } catch (Exception e) {
                        log.error("******************************************");
                        log.error("【获取值，反射异常】field name：{}, 原始对象：{}，具体异常为：", field.getName(), instance, e);
                        log.error("******************************************");
                    }
                }
            }
        }

        return instance;
    }

    private String encryptFieldValue(String originalValue) {
        if (StringUtils.isNotBlank(originalValue)) {
            try {
                SecretContextUtil.SecretContext secretContext = new SecretContextUtil.SecretContext();
                AppConfigProperties configProperties = ApplicationContextUtil.getBean(AppConfigProperties.class);
                String keyAES128 = configProperties.isDevEnv() ? configProperties.getKeyAES128() : AESUtil.getKeyAES_128();
                secretContext.setKeyAES128(keyAES128);
                secretContext.setSecretAES128(RSAUtil.encryptWithPrivateKey(keyAES128,configProperties.getPrivateKeyStr()));
                if (configProperties.isDevEnv()) {
                    SecretContextUtil.setSecretContext(secretContext);
                    return AESUtil.encrypt(keyAES128, originalValue);
                } else {
                    byte[] bytes = AESUtil.generateIV();
                    secretContext.setIvAES(Base64.getEncoder().encodeToString(bytes));
                    SecretContextUtil.setSecretContext(secretContext);
                    return AESUtil.encrypt(keyAES128, originalValue, bytes);
                }
            } catch (Exception e) {
                SecretContextUtil.clear();
                throw new CommonException(ErrorTypeEnum.KEY_AES_128_ENCRYPT_ERROR);
            }
        }

        return null;
    }

}
